package project2.ui.game;

import project2.config.Config;
import project2.config.ImageConstants;
import project2.entity.bullet.Bullet;
import project2.entity.enemy.EnemyPlane;
import project2.entity.my.MyPlane;
import project2.entity.weapon.CatchableWeapon;
import project2.factory.CatchableWeaponFactory;
import project2.factory.EnemyPlaneFactory;
import project2.resources.Sounds;
import project2.type.BulletType;
import project2.type.CatchableWeaponType;
import project2.type.EnemyPlaneType;
import project2.ui.game.auto.*;
import project2.ui.game.operate.MyPlaneMove;
import project2.ui.game.operate.UseBomb;
import project2.util.WaitingFor;

import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 游戏面板
 */
public class GamePlayingPanel extends JPanel {
    private static final long serialVersionUID = 1L;
    // 组件
    public AtomicInteger score;// 积分
    public MyPlane myPlane;// 主角
    public List<EnemyPlane> enemyPlanes;// 敌人
    public List<Bullet> bullets;// 子弹
    public CatchableWeapon popBomb;// 可拾取武器：炸弹
    public CatchableWeapon popDoubleLaser;// 可拾取武器：双排子弹
    // 自动功能
    public final ScoreShow scoreShow = new ScoreShow(this);// 积分展示
    public final BombShow bombShow = new BombShow(this);// 炸弹数展示
    public final BulletsMove bulletsMove = new BulletsMove(this);// 子弹移动
    public final EnemyPlaneMove enemyPlaneMove = new EnemyPlaneMove(this);// 敌机移动
    public final CatchableWeaponMove catchableWeaponMove = new CatchableWeaponMove(this);// 可拾取武器移动
    // 人工操作
    public final MyPlaneMove myPlaneMove = new MyPlaneMove(this);// 操作飞机移动
    public final UseBomb useBomb = new UseBomb(this);// 飞机扔炸弹
    // 定时器（组件定时投放、主角武器定时失效）
    private final WaitingFor wfPopSmallPlane = new WaitingFor(Config.POP_SMALL_ENEMY_PLANE_INTERVAL, Config.GAME_PANEL_REPAINT_INTERVAL);
    private final WaitingFor wfPopBigPlane = new WaitingFor(Config.POP_BIG_ENEMY_PLANE_INTERVAL, Config.GAME_PANEL_REPAINT_INTERVAL);
    private final WaitingFor wfPopBossPlane = new WaitingFor(Config.POP_BOSS_ENEMY_PLANE_INTERVAL, Config.GAME_PANEL_REPAINT_INTERVAL);
    private final WaitingFor wfPopBomb = new WaitingFor(Config.POP_BOMBO_INTERVAL, Config.GAME_PANEL_REPAINT_INTERVAL);
    private final WaitingFor wfPopDoubleLaser = new WaitingFor(Config.POP_DOUBLE_LASER_INTERVAL, Config.GAME_PANEL_REPAINT_INTERVAL);
    private final WaitingFor wfDoubleLaserRunOut = new WaitingFor(Config.DOUBLE_LASER_LAST_TIME, Config.GAME_PANEL_REPAINT_INTERVAL);

    public GamePlayingPanel() throws LineUnavailableException, UnsupportedAudioFileException, IOException {
        this.setSize(Config.MAIN_FRAME_WIDTH, Config.MAIN_FRAME_HEIGHT);// 宽高
        this.setDoubleBuffered(true);// 双缓存（绘画使用）
        this.setOpaque(false);// 透明
        this.addMouseMotionListener(myPlaneMove);// 鼠标移动监听器——操作飞机移动
        this.addMouseListener(useBomb);// 鼠标点击监听器——飞机扔炸弹
    }

    /**
     * 开始游戏
     */
    public void startGame() {
        this.score = new AtomicInteger(0);// 积分
        this.myPlane = new MyPlane(this);// 主角
        this.myPlane.setAlive(true);
        this.myPlane.setPosX((Config.MAIN_FRAME_WIDTH - ImageConstants.MY_PLANE_WIDTH) / 2);
        this.myPlane.setPosY(Config.MAIN_FRAME_HEIGHT - ImageConstants.MY_PLANE_HEIGHT);
        this.bullets = Collections.synchronizedList(new LinkedList<>());// 子弹
        this.enemyPlanes = Collections.synchronizedList(new LinkedList<>());// 敌机

        // 初始化组件投放前的逗留时间
        this.wfPopSmallPlane.init();
        this.wfPopBigPlane.init();
        this.wfPopBossPlane.init();
        this.wfPopBomb.init();
        this.wfPopDoubleLaser.init();
        this.wfDoubleLaserRunOut.init();

        Sounds.gameMusicSoundPlayer.loop();// 音乐循环播放
        Sounds.fireBulletSoundPlayer.loop();

        new Thread(new PaintThread()).start();// 开启线程执行：循环绘制动画图像
    }

    /**
     * 游戏结束
     */
    public void stopGame() {
        this.myPlane.setAlive(false);
        Sounds.gameMusicSoundPlayer.stop();
        Sounds.fireBulletSoundPlayer.stop();
        Sounds.bossPlaneFlyingSoundPlayer.stop();
        Sounds.gameOverSoundPlayer.play();
    }

    class PaintThread implements Runnable {

        @Override
        public void run() {
            while (myPlane.isAlive()) {// 循环绘制每一帧，一直到主角死亡
                // 1.已有组件移动
                // 1.1.子弹移动
                for (int i = 0; i < bullets.size(); i++) {
                    Bullet b = bullets.get(i);
                    bulletsMove.run(b);
                }
                // 1.2.敌机移动
                for (int i = 0; i < enemyPlanes.size(); i++) {
                    EnemyPlane enemyPlane = enemyPlanes.get(i);
                    enemyPlaneMove.run(enemyPlane);
                }
                // 1.3.可拾取武器：炸弹移动
                if (popBomb != null) {
                    catchableWeaponMove.run(popBomb);
                }
                // 1.4.可拾取武器：双排子弹移动
                if (popDoubleLaser != null) {
                    catchableWeaponMove.run(popDoubleLaser);
                }

                // 2.新组件投放
                // 2.1.投放敌机：小型敌机
                wfPopSmallPlane.runFor(() -> {
                    EnemyPlane smallPlane = EnemyPlaneFactory.createEnemyPlane(GamePlayingPanel.this, EnemyPlaneType.SMALL_ENEMY_PLANE);
                    enemyPlanes.add(smallPlane);
                });
                // 2.2.投放敌机：大型敌机
                wfPopBigPlane.runFor(() -> {
                    EnemyPlane bigPlane = EnemyPlaneFactory.createEnemyPlane(GamePlayingPanel.this, EnemyPlaneType.BIG_ENEMY_PLANE);
                    enemyPlanes.add(bigPlane);
                });
                // 2.3.投放敌机：Boss机
                wfPopBossPlane.runFor(() -> {
                    EnemyPlane bossPlane = EnemyPlaneFactory.createEnemyPlane(GamePlayingPanel.this, EnemyPlaneType.BOSS_ENEMY_PLANE);
                    enemyPlanes.add(bossPlane);
                    Sounds.bossPlaneFlyingSoundPlayer.loop();// Boss机专属声音
                });
                // 2.4.投放可拾取武器：炸弹
                wfPopBomb.runFor(() -> {
                    popBomb = CatchableWeaponFactory.createCatchableWeapon(GamePlayingPanel.this, CatchableWeaponType.BOMB);
                    Sounds.popWeaponSoundPlayer.play();
                });
                // 2.5.投放可拾取武器：双排子弹
                wfPopDoubleLaser.runFor(() -> {
                    popDoubleLaser = CatchableWeaponFactory.createCatchableWeapon(GamePlayingPanel.this, CatchableWeaponType.DOUBLE_LASER);
                    Sounds.popWeaponSoundPlayer.play();
                });

                // 3.主角武器失效重置
                // 3.1.双排子弹失效
                wfDoubleLaserRunOut.runFor(() -> {
                    myPlane.setBulletType(BulletType.YELLOW_BULLET);
                    popDoubleLaser = null;
                });
                // 3.2.炸弹失效
                if (popBomb != null && popBomb.isWeaponDisappear()) {
                    popBomb = null;
                }
                // 3.3.双排子弹失效
                if (popDoubleLaser != null && popDoubleLaser.isWeaponDisappear()) {
                    popDoubleLaser = null;
                }

                // 4.面板重绘
                GamePlayingPanel.this.repaint();

                // 5.等待一段时间再绘制，这里参考“人眼观看动画的间隔时长”配置时间
                try {
                    Thread.sleep(Config.GAME_PANEL_REPAINT_INTERVAL);
                } catch (InterruptedException ignored) {
                }
            }
        }

    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        scoreShow.run(g);// 绘制分数
        bombShow.run(g);// 绘制炸弹数
        myPlane.draw(g);// 绘制主角
        for (int i = 0; i < this.enemyPlanes.size(); i++) {// 绘制每个敌机
            EnemyPlane enemyPlane = this.enemyPlanes.get(i);
            enemyPlane.draw(g);
        }
        for (int i = 0; i < this.bullets.size(); i++) {// 绘制每个子弹
            Bullet b = this.bullets.get(i);
            b.draw(g);
        }
        if (this.popBomb != null && !this.popBomb.isWeaponDisappear()) {// 绘制可拾取武器：炸弹
            this.popBomb.draw(g);
        }
        if (this.popDoubleLaser != null && !this.popDoubleLaser.isWeaponDisappear()) {// 绘制可拾取武器：双排子弹
            this.popDoubleLaser.draw(g);
        }
    }

    /**
     * 获取画板，绘制行为都在此画板上执行
     */
    public Graphics getGameGraphics() {
        return this.getComponentGraphics(this.getGraphics());
    }
}
